﻿// ******************************************************
// Copyright © 2010 DCOM Productions®, 
// All Rights Reserved
// ******************************************************

namespace BitFlex.EnterpriseServices.Authentication {
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Microsoft.Win32;
using System.Security.Permissions;

    /// <summary>
    /// Performs basic enterprise level authentication against the Windows Registry
    /// </summary>
    public class RegistryAuthentication<TUser> : IAuthenticationService<TUser> where TUser : ISecureUser, new() {
        /// <summary>
        /// Initializes a new instance of the BitFlex.EnterpriseServices.Authentication.RegistryAuthentication class
        /// </summary>
        public RegistryAuthentication() {
            DataSourceMap = new RegistryAuthenticationKeyMap();
        }

        #region Properties

        /// <summary>
        /// Gets or sets the mapping that defines the registry key and its associated values
        /// </summary>
        public RegistryAuthenticationKeyMap DataSourceMap {
            get;
            set;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Maps the registry authentication service to the specified key and values in the registry datasource
        /// </summary>
        /// <param name="tableName">The full path of the registry key to map</param>
        /// <param name="nameColumn">The name of the registry value that stores the user's name to map</param>
        /// <param name="passwordColumn">The name of the registry value that stores the user's password to map</param>
        public void MapDataSource(string keyRoot, string nameValue, string passwordValue) {
            DataSourceMap.KeyRoot = keyRoot;
            DataSourceMap.NameValue = nameValue;
            DataSourceMap.PasswordValue = passwordValue;
        }

        private string ReadRegistryValue(string valueName) {
            object obj = Registry.GetValue(DataSourceMap.KeyRoot, valueName, null);
            if (obj == null) {
                return null;
            }
            else {
                string val = obj.ToString();
                return val;
            }
        }

        #endregion

        #region IAuthenticationService<TUser> Members

        private Encoding m_Encoding = Encoding.ASCII;
        /// <summary>
        /// Gets or sets the encoding used when altering passwords during encryption
        /// </summary>
        public Encoding Encoding {
            get {
                return m_Encoding;
            }
            set {
                m_Encoding = value;
            }
        }

        private EncryptionType m_Encryption = EncryptionType.Raw;
        /// <summary>
        /// Gets or sets the type of enterprise encryption that will be used when sending passwords
        /// </summary>
        public EncryptionType Encryption {
            get {
                return m_Encryption;
            }
            set {
                m_Encryption = value;
            }
        }

        /// <summary>
        /// Authenticates the specified user against the registry datasource
        /// </summary>
        /// <param name="user">The user to authenticate</param>
        /// <returns>Returns a <see cref="AuthenticationResult"/> enumeration</returns>
        public AuthenticationResult Authenticate(TUser user) {
            string name = ReadRegistryValue(DataSourceMap.NameValue);
            if (name != null) {
                if (name.ToLower() == user.Name.ToLower()) {
                    string password = ReadRegistryValue(DataSourceMap.PasswordValue);
                    if (password != null) {
                        if (password == user.Password) {
                            return AuthenticationResult.Success;
                        }
                        else {
                            return AuthenticationResult.IncorrectPassword;
                        }
                    }
                    else {
                        return AuthenticationResult.Error;
                    }
                }
                else {
                    return AuthenticationResult.UserNotFound;
                }
            }
            else {
                return AuthenticationResult.Error;
            }
        }

        /// <summary>
        /// Encrypts the specified password using Enterpise level encryption
        /// </summary>
        /// <param name="password">The password to encrypt</param>
        /// <returns>Returns the fully encrypted password</returns>
        public string EncryptPassword(string password) {
            switch (this.Encryption) {
                case EncryptionType.Md5:
                    return EncryptionHelper.GetMd5EncryptedPassword(this.Encoding, password);
            }
            return password; // BitFlex.EnterpriseServices.Authentication.EncryptionType.Raw
        }

        #endregion
    }
}